package com.techbh.ridecall;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

//import com.admob.android.ads.AdManager;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;


//TODO revisar permissoes 
public class RideCall extends Activity {

	//public static final String PREFS_NAME = "RideCallPrefs.cfg";

	//Codigos para atividades que retornarão resultados
	private static final int CODE_PICK_CONTACT = 1;
	private static final int CODE_PICK_GEOLOCATION = 2;
	private static final int CODE_SETUP_GPS = 3;

	//Marca para depuração no log do android
	public static final String APPTAG = "RideCall";

	//
	public Location loc;
	public LocationManager lm;
	public LocationProvider lp;
	public TelephonyManager tm;
	public TelephonyManager telephony; 

	public EntidadeAlerta eAlerta = null;

	protected Notificador notificador; 

	protected SharedPreferences config = null;
	protected SharedPreferences config_private = null;
	
	protected GeoUtil geoutil = null;
	
	protected Location lastKnowLocation = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		Context ct = getBaseContext();
		ct = getApplicationContext();

		popularRaios(ct);

		popularExpira(ct);

		//Restaura as preferências do usuário
		restauraConfiguracoes();

		//Registra operação de chamada para o botão de chamar
		tratamentoBotaoChamar();

		//Registra um intenta para escolha de telefone do contato
		tratamentoBotaoBuscaContato();

		//Registra um intenta para escolha de telefone do contato
		tratamentoBotaoEnviarSMS();

		//Registra o alerta de proximidade para os valores informados
		tratamentoBotaoRegistroAlerta();

		//Registra um alerta de proximidade com acao de chamada no retorno
		tratamentoBotaoRegistroAlertaChamada();

		//Vai para o mapa pra facilitar a entrada do local
		tratamentoBotaoBuscarLocal();

		eAlerta = new EntidadeAlerta(ct);


		//Testa se tem gps para poder usar o programa
		checkLocationProviders();
		//testaLocationProvider();

		//configura elementos de telefonia
		setupTelefonia(ct);
		
		/*
		AdManager.setTestDevices( new String[] {
				AdManager.TEST_EMULATOR, // Android emulator
				"E83D20734F72FB3108F104ABC0FFC738", // My T-Mobile G1 Test Phone
				"20101109-ANDROID-3312276cc1406347",
				} );
		*/
		
		notificador = new Notificador(ct);
		
		geoutil = new GeoUtil(ct);
		geoutil.setBaseLocation(lastKnowLocation);
	}


	public void setupTelefonia(Context ct){

		tm = (TelephonyManager) ct.getSystemService(Context.TELEPHONY_SERVICE);

	}


	/**
	 * This method is called when the sending activity has finished, with the
	 * result it supplied.
	 * 
	 * @param requestCode The original request code as given to startActivity().
	 * @param resultCode From sending activity as per setResult().
	 * @param data From sending activity as per setResult().
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		//@note Quais são os codigos possíveis para resultCode???

		// This is a standard resultCode that is sent back if the
		// activity doesn't supply an explicit result.  It will also
		// be returned if the activity failed to launch.
		if (resultCode == RESULT_OK) {
			switch (requestCode) {
			case CODE_PICK_CONTACT:
				//Tratar as informações do contato escolhido
				tratarResultadoEscolhaContato(data);
				break;
			case CODE_PICK_GEOLOCATION:
				tratarResultadoLocalEscolhido(data);
				break;
			case CODE_SETUP_GPS:
				//trataConfiguracaoGPS();
				testaLocationProvider();
			}

		} else {
			// TODO: remover
			Log.d(APPTAG, "O resultado do pedido da atividade " + requestCode + " falhou.");

			if(requestCode == CODE_SETUP_GPS){
				//O usuário pode ter modificado o flag e pediu pra sair da tela de configuração
				//trataLocalizacaoFail();
				testaLocationProvider();
			}
		}
	}


	public void tratarResultadoLocalEscolhido(Intent data) {

		EditText editLatLng = (EditText) findViewById(R.id.editLatLng);

		//Obtem os parametros retornados
		Bundle dados = data.getExtras();

		//Monta as chaves e valores de cada um
		Set<String> parametros = dados.keySet();
		Iterator<String> iter = parametros.iterator();
		while (iter.hasNext()) {
			String key = (String) iter.next();
			Log.v(APPTAG, key + "[" + dados.get(key) + "]");
		}

		double lat = dados.getDouble("lat"); 
		double lng = dados.getDouble("lng");
		String local = dados.getString("local"); //lat,lng

		eAlerta.lat = lat;
		eAlerta.lng = lng;

		//Preenche o valor representativo do local com latitude ou endereço
		editLatLng.setText(local);

		Log.i(APPTAG, "Resultado da busca de local: lat "+lat+" long "+lng );

	}



	public void tratarResultadoEscolhaContato(Intent data){

		Bundle extras = data.getExtras();
		try {
			Set<String> chaves = extras.keySet();
			Iterator<String> iterate = chaves.iterator();
			while (iterate.hasNext()) {
				String chave = (String) iterate.next();
				// TODO: remover
				Log.v(APPTAG, chave + "[" + extras.get(chave) + "]");
			}

		} catch (NullPointerException e) {
			// TODO: remover
			Log.v(APPTAG, "Nao havia extras para o contato escolhido!");
		}

		Uri result = data.getData();
		/* Exemplo de Uri = 
		 * content://com.android.contacts/contacts/lookup/0r7-2C46324E483C324A3A484634/7
		 * content://com.android.contacts/contacts/lookup/0n292D43/1
		 * 
		 * A parte importante é a última pois indica o ID do contato
		 * : 7 no primeiro exemplo
		 * : 1 no segundo exemplo
		 */
		Log.v(APPTAG, "Resultado obtido: " + result.toString());

		// obtem o ID do contato pela Uri
		String contactId = result.getLastPathSegment();

		ContentResolver cr = getContentResolver();

		//Busca todos os telefones encontrados

		Context ct = getBaseContext();
		String numero = "";
		int num_telefones = 0;
		ArrayAdapter<String> telefones = new ArrayAdapter<String>(ct, 0);

		// Obtem todos os telefones do contato
		Cursor cphones = cr.query( Phone.CONTENT_URI, null, 
				Phone.CONTACT_ID + "=?", new String[]{contactId}, null);
		try {

			while (cphones.moveToNext()) {
				numero = cphones.getString(cphones.getColumnIndex(Phone.NUMBER));
				int type = cphones.getInt(cphones.getColumnIndex(Phone.TYPE));

				switch (type) {
				case Phone.TYPE_HOME://Adicionar esse também?
				case Phone.TYPE_MOBILE:
				case Phone.TYPE_WORK:
					telefones.add(numero);
					Log.v(APPTAG, "Telefone encontrado: " + numero);
					break;
				}
			}
			cphones.close();
		} catch (NullPointerException e) {
			Toast.makeText(this, "NullPointerException ", Toast.LENGTH_LONG).show();
		} catch (RuntimeException e) {
			Toast.makeText(this, "RuntimeException", Toast.LENGTH_LONG).show();
		}

		num_telefones = telefones.getCount();

		if(num_telefones == 0){
			//Mostra que não há telefones para o contato
			Toast.makeText(this, "Esse contato não tem telefone.", Toast.LENGTH_LONG).show();
			Log.v(APPTAG, "Sem telefones para esse contato! " );

		} else if(num_telefones == 1){
			//irá inserir direto no campo
			//numero = telefones.getItem(0);
			EditText editTelefone = (EditText) findViewById(R.id.editTelefone);
			editTelefone.setText(numero);
			Log.v(APPTAG, "Telefone inserido: " + numero);

		} else {

			Log.v(APPTAG, "O contato tem vários telefones!");
			//Popula os telefones num formato para usar no dialogo
			final CharSequence[] csTelefones = new CharSequence[num_telefones];
			for (int i = 0; i < csTelefones.length; i++) {
				csTelefones[i] = telefones.getItem(i);
			}
			//Mostra um dialogo para que seja escolhido o telefone
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setTitle("Escolha um número");

			//Funciona mas não cancela o menu, eu teria que ativar os botões de ok e cancel
			//builder.setSingleChoiceItems(csTelefones, 0, new DialogInterface.OnClickListener() {

			builder.setItems(csTelefones, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int item) {
					String tel_escolhido = (String) csTelefones[item];
					EditText e = (EditText)findViewById(R.id.editTelefone);
					e.setText(tel_escolhido);

					//Toast.makeText(getApplicationContext(), tel_escolhido, Toast.LENGTH_SHORT).show();
				}
			});

			try {
				builder.show();
			} catch (Exception e) {
				Toast.makeText(getApplicationContext(), "Exceção", Toast.LENGTH_SHORT).show();
			}
		}

	}



	public void mostrarEstado(){
		Context ct = getBaseContext();

		int estado = tm.getCallState();
		String testado = "";


		switch(estado){
		case TelephonyManager.CALL_STATE_IDLE:
			testado = "atoa";
			break;
		case TelephonyManager.CALL_STATE_OFFHOOK:
			testado = "fora do gancho";
			break;
		case TelephonyManager.CALL_STATE_RINGING:
			testado = "chamando";
			break;
		}

		String base = "Estado do telefone:" ;
		String msg = base + " "  + testado + "-" + String.valueOf(estado);
		Toast.makeText(ct, msg , Toast.LENGTH_LONG).show();

		Log.w(APPTAG, msg);
	}


	public void chamarDireto(){

		Context ct = getBaseContext();
		EditText editTel = (EditText) findViewById(R.id.editTelefone);

		String numero = editTel.getText().toString().trim();
		if( (numero.length() == 0) ){
			editTel.requestFocus();

			String msg = " Preencha o numero de telefone ";
			Toast.makeText(ct, msg , Toast.LENGTH_LONG).show();

			Log.w(APPTAG, msg);
			return;
		} 

		Uri tel_chamar = Uri.parse("tel:" + numero);
		//Se usarmos ACTION_DIAL será apresentado o discador
		//Se usarmos ACTION_CALL será feita a chamada diretamente

		Intent intent = new Intent(Intent.ACTION_CALL);
		intent.setData( tel_chamar );
		try {
			startActivity(intent);
		} catch (ActivityNotFoundException e ){
			Toast.makeText(ct, "Este dispositivo não permite efetuar chamadas!" , Toast.LENGTH_LONG).show();
		}

	}


	public void chamarActivity(){

		Context ct = getBaseContext();
		EditText editTel = (EditText) findViewById(R.id.editTelefone);

		String numero = editTel.getText().toString().trim();
		if( (numero.length() == 0) ){
			editTel.requestFocus();

			String msg = " Preencha o numero de telefone ";
			Toast.makeText(ct, msg , Toast.LENGTH_LONG).show();

			Log.w(APPTAG, msg);
			return;
		} 

		Uri tel_chamar = Uri.parse("tel:" + numero);
		Intent i = new Intent("com.techbh.ridecall.RCPhone");
		i.setData( tel_chamar );
		//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//preciso disso?
		try {
			startActivity(i);
		} catch (ActivityNotFoundException e ){
			Toast.makeText(ct, "Este dispositivo não permite efetuar chamadas!" , Toast.LENGTH_LONG).show();
		}

	}



	public void enviarSMS(String numero, String mensagem){
		boolean modo_um = false;
		Context ct = getBaseContext();

		if(numero.length() == 0){
			Toast.makeText(ct, "Digite o número do telefone para permitir enviar o sms!" , Toast.LENGTH_LONG).show();
		}

		if(modo_um){
			/* Vai para a tela de mensagem (não envia direto) */
			Uri smsUri = Uri.parse("smsto:" + numero);  
			Intent intent = new Intent(Intent.ACTION_VIEW, smsUri);  
			intent.putExtra("sms_body", mensagem);  
			intent.putExtra("address", numero);  
			intent.setType("vnd.android-dir/mms-sms");
			try {
				startActivity(intent);  
			} catch (ActivityNotFoundException e ){
				Toast.makeText(ct, "Este dispositivo não permite enviar SMS!" , Toast.LENGTH_LONG).show();
			}

		} else {

			SmsManager smsMg = SmsManager.getDefault();

			//Testar também com Uri diferente: sms: e smsto:
			Uri smsUri = Uri.parse("sms:" + numero);  

			//Testar também com actions diferentes: SENDTO
			Intent sentI = new Intent(Intent.ACTION_SEND, smsUri);  
			sentI.setType("vnd.android-dir/mms-sms");   
			sentI.putExtra("sms_body", mensagem);  

			PendingIntent pi = PendingIntent.getActivity(this, 0, sentI, 0);                

			String scAddress = null;	//service center address
			PendingIntent deliveryIntent = null;//será broadcasted quando o destinatario receber o sms
			smsMg.sendTextMessage(numero, scAddress, mensagem, pi, deliveryIntent);

		}

	}




	public void popularRaios(Context ct){
		//Popula o spinner para o raio de alerta  
		Spinner raios = (Spinner) findViewById(R.id.spRaios);
		//Cria o adapter lendo direto dos resources (poderia ser da responsta de uma função)
		ArrayAdapter<CharSequence> adapter_raio = ArrayAdapter.createFromResource(
				this, R.array.spRaios, android.R.layout.simple_spinner_item);
		//Modifica o modo de visao 
		adapter_raio.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		raios.setAdapter(adapter_raio);    	
	}



	public void popularExpira(Context ct){
		//Popula o spinner para o raio de alerta  
		Spinner expira = (Spinner) findViewById(R.id.spExpira);
		//Cria o adapter lendo direto dos resources (poderia ser da responsta de uma função)
		ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
				this, R.array.spExpira, android.R.layout.simple_spinner_item);
		//Modifica o modo de visao 
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		expira.setAdapter(adapter);    	
	}



	public void tratamentoBotaoBuscaContato(){
		Button btnEscolherContato = (Button) findViewById(R.id.btnPickContact);
		//Define a operação que será atribuida ao mesmo
		//Operação debug, mostrar o estado do telefone
		OnClickListener listener2 = new OnClickListener(){
			public void onClick(View v){

				EditText editTel = (EditText) findViewById(R.id.editTelefone);
				Intent i = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
				try{
					startActivityForResult(i, CODE_PICK_CONTACT);
				} catch (ActivityNotFoundException e ){
					Context ct = getBaseContext();
					Toast.makeText(ct, "Este dispositivo não permite a busca de contatos!" , Toast.LENGTH_LONG).show();

					editTel.requestFocus();
				}

			}
		};
		btnEscolherContato.setOnClickListener(listener2);

		EditText editTel = (EditText) findViewById(R.id.editTelefone);
		editTel.addTextChangedListener(new TextWatcher() { 
			public void  afterTextChanged(Editable s){ 
				Log.d(APPTAG, "editTel - afterTextChanged"); 
			} 
			public void  beforeTextChanged(CharSequence s, int start, int 
					count, int after){ 
				Log.d(APPTAG, "editTel - beforeTextChanged"); 
			} 
			public void  onTextChanged  (CharSequence s, int start, int before, 
					int count) { 
				Log.d(APPTAG, "editTel - onTextChanged"); 
				onStart();
			}
		});
	}


	public void tratamentoBotaoBuscarLocal(){
		Button btnBuscarLocal = (Button) findViewById(R.id.btnBuscarLocal);
		OnClickListener listener1 = new OnClickListener(){
			public void onClick(View v){
				Intent i = new Intent(RideCall.this, BuscarLocalActivity.class);        
				startActivityForResult(i, CODE_PICK_GEOLOCATION);
			}
		};
		btnBuscarLocal.setOnClickListener(listener1);

		EditText local = (EditText) findViewById(R.id.editLatLng);
		local.addTextChangedListener(new TextWatcher() { 
			@Override
			public void  afterTextChanged (Editable s){ 
				Log.d(APPTAG, "local - afterTextChanged");
				if(s.toString().length() > 10){
					geoutil.obterLatLngDoEndereco(s.toString());
				}
			} 
			public void  beforeTextChanged  (CharSequence s, int start, int 
					count, int after){ 
				Log.d(APPTAG, "local - beforeTextChanged"); 
			} 
			public void  onTextChanged  (CharSequence s, int start, int before, 
					int count) { 
				Log.d(APPTAG, "local - onTextChanged"); 
				onStart();
			}
		});

	}



	public void tratamentoBotaoChamar(){
		Button btnChamar = (Button) findViewById(R.id.btnChamar);
		//Define a operação que será atribuida ao mesmo
		//Operação debug, mostrar o estado do telefone
		OnClickListener listener1 = new OnClickListener(){
			public void onClick(View v){
				chamarDireto();
				//chamarActivity();
			}
		};
		btnChamar.setOnClickListener(listener1);
	}


	public void tratamentoBotaoEnviarSMS(){
		Button btnEnviarSMS = (Button) findViewById(R.id.btnEnviarSMS);
		//Define a operação que será atribuida ao mesmo
		//Operação debug, mostrar o estado do telefone
		OnClickListener listener3 = new OnClickListener(){
			public void onClick(View v){
				EditText editTel = (EditText) findViewById(R.id.editTelefone);
				String numero = editTel.getText().toString().trim();

				EditText editSMS = (EditText) findViewById(R.id.editSMS);
				String mensagem = editSMS.getText().toString().trim();

				if(numero.length() > 0 ){
					if( mensagem.length() > 0 ){
						enviarSMS(numero, mensagem);
					} else {
						Context ct = getBaseContext();
						Toast.makeText(ct, "Digite alguma mensagem!" , Toast.LENGTH_LONG).show();		    		
						editSMS.requestFocus();
					}
				} else {
					Context ct = getBaseContext();
					Toast.makeText(ct, "Digite algum número!" , Toast.LENGTH_LONG).show();		    		
					editTel.requestFocus();

				}
			}
		};
		btnEnviarSMS.setOnClickListener(listener3);
	}


	public void tratamentoBotaoRegistroAlerta(){

		ToggleButton btnRegistrarAlerta = (ToggleButton) findViewById(R.id.btnRegistrarAlerta);

		//Comuta o estado inicial do botão de registro do alerta
		/* TODO checar se existe o pendingintent associado ao alerta
		 * para indicar corretamente o estado do botao
		 */


		//Registra o click para ativar/desativar o alerta de proximidade
		OnClickListener listener = new OnClickListener(){

			public void onClick(View v){
				ToggleButton btnRegistrarAlerta = (ToggleButton) findViewById(R.id.btnRegistrarAlerta);
				Bundle b = new Bundle();
				boolean ativar = false;
				boolean executado = false;

				b.putBoolean("ativado", btnRegistrarAlerta.isChecked());

				Log.d(APPTAG," Comuta o alerta de proximidade para o endereço!");

				//isChecked é verificado após o clique no objeto
				if(btnRegistrarAlerta.isChecked()){
					//Ativar 
					Log.d(APPTAG," vai pedir ativação");
					ativar = true;

				} else {
					//Desativar
					Log.d(APPTAG," vai pedir desativação");
					ativar = false;

				}
				Uri data = null;
				executado = configuraAlertaProximidade(ativar, b, data);
				if(ativar && !executado){
					btnRegistrarAlerta.setChecked(false);
				}

			}
		};
		btnRegistrarAlerta.setOnClickListener(listener);			

	}


	/* 
	 * return false = não conseguiu configurar
	 * return true = conseguiu configurar
	 * */
	public boolean configuraAlertaProximidade(boolean ativar, Bundle b, Uri data){
		Intent iAP;
		Context ct = getBaseContext();

		if(!syncEntidadeAlerta()){
			Toast.makeText(ct, "Preencha os parametros necessarios: tel, sms, lat-lng" , Toast.LENGTH_SHORT).show();
			Log.d(APPTAG, "O usuário não preencheu todos os campos");
			return false;
		}

		//TODO colocar esse teste em um lugar separado e desabilitar o controle de ativação do alerta
		if(lm == null){
			Toast.makeText(ct, "Esse dispositivo não permite o registro de alerta" +
					" de proximidade pois não tem localizadores disponíveis" ,
					Toast.LENGTH_LONG).show();
			Log.d(APPTAG, "Não havia sistema de localização para registrar o alerta");
			return false;
		}


		if(ativar){
			Toast.makeText(ct, "Ativando o alerta de proximidade:" , Toast.LENGTH_LONG).show();

			boolean real = true;
			if(real){
				Log.d(APPTAG, "Usando o modo real de alerta");
				registraAlertaProximidade(eAlerta);
				
				notificador.informaRegistroAlerta(eAlerta.tel, eAlerta.metodo, eAlerta.local);
				
			} else {
				//TODO passar isso aqui para a classe de testes
				Log.d(APPTAG, "Testando intent...");
				boolean eAlertaIntent = false;
				if(eAlertaIntent){
					Log.d(APPTAG, " do eAlerta");
					iAP = eAlerta.getIntent(ct);
				} else {
					Log.d(APPTAG, "montado diretamente");

					String action = "PROXIMITY_ALERT";
					iAP = new Intent(action);	//Modo Action
					//Intent i = new Intent(ct, ProximityReceiver.class);	//Modo Direto
					if(data != null){
						iAP.setData(data);
					}
				}

				try {
					//Faz o teste do intent diretamente
					sendBroadcast(iAP);
				} catch (RuntimeException e){
					Toast.makeText(ct, "Não foi possível executar o tratamento de alerta de proximidade:" , Toast.LENGTH_LONG).show();
				}
			}

		} else {
			Toast.makeText(ct, "Desativando o alerta de proximidade:" , Toast.LENGTH_LONG).show();
			removeAlertaProximidade(eAlerta);
			notificador.excluiRegistroAlerta(eAlerta.tel);
		}
		return true;
	}



	public void registraAlertaProximidade(EntidadeAlerta ea){
		Context ctx = getApplicationContext(); //getBaseContext();

		Log.d(APPTAG, "Registro efetivo do alerta");

		PendingIntent pi = ea.getPendingIntent(ctx);
		long validade = ea.validade;	//em segundos
		validade *= 1000;

		lm.addProximityAlert(ea.lat, ea.lng, ea.raio, validade, pi);
	}


	public void removeAlertaProximidade(EntidadeAlerta ea){
		Context ctx = getApplicationContext(); //getBaseContext();

		PendingIntent pi = ea.getPendingIntent(ctx);
		lm.removeProximityAlert(pi);
	}





	public void tratamentoBotaoRegistroAlertaChamada(){

		//Comuta o estado inicial do botão de toggle de modo aviao
		Button btnRegistrarAlertaChamada = (Button) findViewById(R.id.btnRegistrarAlertaChamada);

		//Registra o click para ativar/desativar o alerta de proximidade
		OnClickListener listener = new OnClickListener(){

			public void onClick(View v){
				Bundle b = new Bundle();
				boolean ativar = false;
				Uri data = null;

				b.putBoolean("ativado", true);

				Log.d(APPTAG," Ativar o alerta de proximidade para o endereço!");
				ativar = true;

				EditText editTel = (EditText) findViewById(R.id.editTelefone);
				String numero = editTel.getText().toString().trim();

				data = Uri.parse("tel:" + numero);

				configuraAlertaProximidade(ativar, b, data);

			}
		};
		btnRegistrarAlertaChamada.setOnClickListener(listener);			

	}


  //TODO otimizar atualização de valores para os que o usuário tem acesso direto
	public boolean syncEntidadeAlerta(){

		//Sincroniza os dados dos campos com os dados internos
		EditText editTel = (EditText) findViewById(R.id.editTelefone);
		String numero = editTel.getText().toString().trim();
		if(numero.length() > 0){
			eAlerta.tel = numero;
		} else {
			return false;
		}

		//Usando valor padrão enquanto não for colocado um campo apropriado
		eAlerta.metodo = "chamada";	//ou sms
		
		/* Esta sendo tratado direto pelo objeto eAlerta
		if(eAlerta.metodo == "sms"){
			EditText editSMS = (EditText) findViewById(R.id.editSMS);
			String mensagem = editSMS.getText().toString().trim();
			if(mensagem.length() > 0){
				eAlerta.msg = mensagem;
			} else {
				return false;
			}
		} else {
			eAlerta.msg = "";
		}
		*/

		//Obter raio
		Spinner raios = (Spinner) findViewById(R.id.spRaios);
		int raio = raios.getSelectedItemPosition();
		switch(raio){
		default:
		case 0:	raio = 100; break;
		case 1:	raio = 200; break;
		case 2:	raio = 500; break;
		case 3:	raio = 1000; break;
		}
		eAlerta.raio = (float) raio;

		//Obter tempo de expiração
		Spinner expira = (Spinner) findViewById(R.id.spExpira);
		int validade = expira.getSelectedItemPosition();
		switch(validade){
		default:
		case 0:	validade = 30 * 60; break;	//30min
		case 1:
		case 2:
		case 3:
			validade = validade * 3600; break;	//horas
		}
		eAlerta.validade = (long) validade;

		//Latitude e Longitude = atualizados na função que volta do mapa
		EditText editLatLng = (EditText) findViewById(R.id.editLatLng);
		if(editLatLng.getText().toString().trim().length() == 0 ){
			//editLatLng.setText("0,0");
		}
		eAlerta.parseLatLng(editLatLng.getText().toString().trim());

		return true;
	}


	//ref: http://stackoverflow.com/questions/843675/how-do-i-find-out-if-the-gps-of-an-android-device-is-enabled
	public void checkLocationProviders(){
		Context ctx = getBaseContext();

		//Verifica se é necessário alterar/habilitar alguma configuração do aparelho
		/*
		 * Não está detectando corretamente
    	if (Settings.Secure.getInt(ctx.getContentResolver(),
    			Settings.Secure.LOCATION_PROVIDERS_ALLOWED, 0) == 0) {
    		Log.d(APPTAG, "Os sistemas de localização não estão habilitados!");
  			buildAlertMessageNoGps();
  			//Settings.ACTION_LOCATION_SOURCE_SETTINGS
  			return;
    	}
		 */

		//Obtem o serviço de localização disponível
		lm = (LocationManager) getSystemService( Context.LOCATION_SERVICE );

		//Só me importa se tem GPS (por enquanto)
		if ( !lm.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
			Log.d(APPTAG, "A localização por satélite GPS não está habilitada!");

			//pede ao usuário para ligar a opção
			buildAlertMessageNoGps();

		} else {
			Log.i(APPTAG, "A localização por satélite GPS está habilitada!");
			atualizaUltimaLocalizacao("gps");

		}

	}

	public void buildAlertMessageNoGps() {
		final AlertDialog.Builder builder = new AlertDialog.Builder(this);

		builder.setMessage("A localização por GPS está desabilitada, você quer habilitá-la?")
		.setCancelable(false)
		.setPositiveButton("Sim", new DialogInterface.OnClickListener() {
			public void onClick( final DialogInterface dialog, final int id) {
				Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
				startActivityForResult(intent, CODE_SETUP_GPS);
			}
		})
		.setNegativeButton("Não", new DialogInterface.OnClickListener() {
			public void onClick( final DialogInterface dialog, final int id) {
				dialog.cancel();
				trataLocalizacaoFail();
			}
		});
		final AlertDialog alert = builder.create();
		alert.show();
	}




	/* TODO revisar isso aqui pois está uma lambança
	 * TODO na primeira versão (brasil) só me importa o GPS 
	 * TODO em outra versão poderei usar a localização por rede também
	 * TODO carregar o spinner de distancia de acordo com a precisão encontrada
	 * */
	public void testaLocationProvider(){
		String p1 = LocationManager.NETWORK_PROVIDER;
		String p2 = LocationManager.GPS_PROVIDER;

		String disponivel = "";
		Criteria criteria = new Criteria();
		List<String> candidatos;
		//String providerName;
		boolean enabled_flag = false;
		Context ctx = getBaseContext();


		lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);

		candidatos = lm.getProviders(criteria, enabled_flag);

		// test that mock locations are allowed so a more descriptive error message can be logged
		if (Settings.Secure.getInt(ctx.getContentResolver(),
				Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
			Log.i(APPTAG, "É possível utilizar localizações falsas (mock locations)");
		}

		//Verifica se é necessário alterar/habilitar alguma configuração do aparelho 
		if (Settings.Secure.getInt(ctx.getContentResolver(),
				Settings.Secure.LOCATION_PROVIDERS_ALLOWED, 0) == 0) {
			Log.i(APPTAG, "Os sistemas de localização não estão habilitados, deseja habilitá-los?");
		}

		//Obtendo provedores existentes no dispositivo
		for (int i=0; i<candidatos.size(); i++) {
			Log.i(APPTAG, "Servidor de geo-localização existente: " + candidatos.get(i));
		}

		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		enabled_flag = true;
		disponivel = lm.getBestProvider(criteria, enabled_flag);
		if(disponivel != null){
			Log.i(APPTAG, "O melhor provedor disponível: " + disponivel);

			try {

				//tenta usar o de redes
				lp = lm.getProvider(p1);
				if (lp != null) {
					disponivel = p1;
					Log.d(APPTAG, "Existe um provedor de Redes(WiFi e Operadora)");
				}
				//tenta melhorar usando o GPS
				lp = lm.getProvider(p2);
				if (lp != null) {
					disponivel = p2;
					Log.d(APPTAG, "Existe um provedor de Satelites");
				}


			} catch(IllegalArgumentException e){
				//Não há nenhum disponível
				Log.e(APPTAG, "Erro no acesso aos servidores de localização!");

			}
		} else {
			Log.e(APPTAG, "Nenhum servidor de localização disponível");

			//Nenhum servidor de localização disponível para uso
			trataLocalizacaoFail();
			return ;
		}

		//De acordo com os provedores disponíveis pode-se orientar o usuário a ligá-los ou indicar que não é possível executar o programa
		Log.i(APPTAG, "Provedor escolhido: " + disponivel);
		
		atualizaUltimaLocalizacao(disponivel);

	}
	
	
	public void atualizaUltimaLocalizacao(String provider){
		if(lm == null){
			return; 
		}
		loc = lm.getLastKnownLocation(provider);
		if (loc == null) {
			Log.e(APPTAG, "Não foi possível obter a última localização via " + provider);
			/*
      	Toast.makeText(this, "Sua última localização não estava disponível. Abortando...",
    			Toast.LENGTH_LONG).show();
			 */
		} else {
			lastKnowLocation = loc;
			
			Log.d(RideCall.APPTAG,"lastKnowLocation = " 
					+ loc.getLatitude() + ", " 
					+ loc.getLongitude() );
		}
	}
	

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_menu, menu);
		return true;
	}

	/* */
	public boolean onOptionsItemSelected(MenuItem item) {
		Intent i ;
		// Handle item selection
		switch (item.getItemId()) {
		case R.id.menu_config:
			i = new Intent(RideCall.this, RideCallConfig.class);
			startActivity(i);
			return true;
		case R.id.menu_about:
			i = new Intent(RideCall.this, RideCallAbout.class);
			startActivity(i);
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
		//return true;
	}



	public void trataLocalizacaoFail(){
		//faz o log
		Log.d(APPTAG, "Sem que o GPS esteja ligado, essa aplicação não irá funcionar!");

		//Talvez seja interessante mostrar no log quais os disponíveis
		//Log.e(APPTAG, "Não há provedores disponíveis!");

		//informa ao usuário que os alertas não irão funcionar
		//mas é possível executar o programa    	
		Toast.makeText(this, "Sem GPS o alerta não irá funcionar!", Toast.LENGTH_LONG).show();

	}


	public void trataLocalizacaoOk(){
		//obtem a ultima localização disponível
		//salva essa localização nas preferências do aplicativos
		//prepara o localizador para que o programa possa utilizá-lo    	
	}




	protected void onStart(){
		super.onStart();  

		//Atualiza elementos da interface
		updateUI();

	}


	protected void onResume(){
		super.onResume();
	}


	//Use onPause() for store persistent data
	protected void onPause(){
		super.onPause();
	}


	protected void onStop(){
		super.onStop();

		//Salva as preferências que foram modificadas
		//Isso não devia estar na tela de configurações ?
		salvaConfiguracoes();
	}


	protected void onDestroy(){
		super.onDestroy();
	}


	protected void onRestart(){
		super.onRestart();
	}


	//Because onSaveInstanceState() is not always called, 
	//you should use it only to record the transient state of the activity, 
	protected void onSaveInstanceState(Bundle outState){
		Log.i(APPTAG, "Salvando estado temporário da atividade");

		/* Coisas a salvar:
		 * - o telefone
		 * - a posicao geografica escolhida lat long
		 */

		EditText editTel= (EditText) findViewById(R.id.editTelefone);
		outState.putString("telefone", editTel.getText().toString().trim() );

		EditText editLatLng = (EditText) findViewById(R.id.editLatLng);    	
		outState.putString("latlng", editLatLng.getText().toString().trim() );

	}


	protected void onRestoreInstanceState(Bundle savedInstanceState){
		Log.i(APPTAG, "Recuperando estado temporário da atividade");
		String valor = "";

		//Restaura o campo do telefone 
		valor = savedInstanceState.getString("telefone");
		EditText editTel= (EditText) findViewById(R.id.editTelefone);
		editTel.setText(valor);

		//Restaura o campo da latitude e longitude 
		valor = savedInstanceState.getString("latlng");
		EditText editLatLng = (EditText) findViewById(R.id.editLatLng);
		editLatLng.setText(valor);

	}



	//TODO revisar: deveria ficar num objeto à parte ?
	//TODO colocar valores e chaves como static final
	public void restauraConfiguracoes(){

		//Inicia as configurações do aplicativo
		Log.d(APPTAG, "Restaurando as preferências...");

		//Preferências privadas desta activity
		config_private = (SharedPreferences) getPreferences(MODE_PRIVATE);

		//Preferências compartilhadas desta aplicação (default)
		config = PreferenceManager.getDefaultSharedPreferences(this);
		//config = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);

		SharedPreferences.Editor editor = config.edit();

		if(!config.contains("cfg_distancia")){
			//As configurações não foram inicializadas ainda
			//Preparar o "espaço" de preferências

			editor.putString("cfg_distancia", "0");
			editor.putString("cfg_validade", "0");
			editor.putString("cfg_metodo", "chamada");

			//sempre vai gerar pois envolve "gastos" 
			//editor.putBoolean("cfg_gerar_notificacao", true);

			editor.commit();

			Log.d(APPTAG, "Configurações inicializadas");

		}
		//Já foi configurado
		Log.d(APPTAG, "-----------------");

		//Ajusta os campos visíveis

		//Usa as configurações salvas para ajustar os campos (quick alert)
		int id_raio = Integer.parseInt( config.getString("cfg_distancia","0") );
		Spinner raios = (Spinner) findViewById(R.id.spRaios);
		raios.setSelection(id_raio);
		Log.d(APPTAG, "O valor configurado para a distancia = " + id_raio);

		int id_validade = Integer.parseInt( config.getString("cfg_validade", "0") );
		Spinner expira = (Spinner) findViewById(R.id.spExpira);
		expira.setSelection(id_validade);
		Log.d(APPTAG, "O valor configurado para a validade = " + id_validade);

		if(config.getBoolean("cfg_salvar_contato",true) == true){
			EditText editTel = (EditText) findViewById(R.id.editTelefone);
			editTel.setText( config.getString("lastContactNumber",""));
		}

		if(config.getBoolean("cfg_salvar_endereco",true) == true){
			EditText editLatLng = (EditText) findViewById(R.id.editLatLng);
			editLatLng.setText( config.getString("lastGeoTarget",""));
		}

	}


	public void salvaConfiguracoes(){

		//Preferências compartilhadas desta aplicação (default)
		config = PreferenceManager.getDefaultSharedPreferences(this);
		SharedPreferences.Editor editor = config.edit();

		//Ultimo contato: nome + telefone
		if(config.getBoolean("cfg_salvar_contato",true)){

			//EditText editContact = (EditText) findViewById(R.id.editContact);
			//editor.putString("lastContact", editContact.getText().toString().trim());

			EditText editTel = (EditText) findViewById(R.id.editTelefone);
			String lastContactNumber = editTel.getText().toString().trim();
			editor.putString("lastContactNumber", lastContactNumber);
		}

		//Ultima posição escolhida: endereço + posição
		if(config.getBoolean("cfg_salvar_endereco",true)){
			//EditText editAddress = (EditText) findViewById(R.id.editAddress);
			//editor.putString("lastAddress", editAddress.getText().toString().trim());

			EditText editLatLng = (EditText) findViewById(R.id.editLatLng);
			String lastGeoTarget = editLatLng.getText().toString().trim();
			editor.putString("lastGeoTarget", lastGeoTarget);
		}

		editor.commit();//Faz o commit das alterações

		Log.d(APPTAG, "Salvando as configurações...");

	}


	public void atualizaPreview(){
		//Itens do preview: contato, método, distancia e endereço
		String contato = "";
		String numero = "";
		String metodo = "";
		String distancia = "";
		String endereco = "";
		String validade = "";

		EditText dummy1 = null;
		EditText dummy2 = null;
		EditText dummy3 = null;

		config = PreferenceManager.getDefaultSharedPreferences(this);
      
		TextView previewAlerta = (TextView)findViewById(R.id.preview_alerta);

		//Contato + Numero
		dummy1 = (EditText) findViewById(R.id.editTelefone);//Nome do contato
		dummy2 = (EditText) findViewById(R.id.editTelefone);
		dummy3 = (EditText) findViewById(R.id.editLatLng);
		
		if((dummy1.length() == 0) || (dummy3.length() == 0) ){
			previewAlerta.setClickable(false);
			previewAlerta.setText("------------");
			return;
		}
		
		
		contato = dummy1.getText().toString().trim();;
		numero = dummy2.getText().toString().trim();;

		//Metodo = obter da configuração
		metodo = config.getString("cfg_metodo", "chamada");

		//Distancia
		int raio = 0;
		distancia = config.getString("cfg_distancia", "0");
		raio = Integer.parseInt(distancia);
		switch(raio){
		default:
		case 0:	distancia = "100m"; break;
		case 1:	distancia = "200m"; break;
		case 2:	distancia = "500m"; break;
		case 3:	distancia = "1km"; break;
		}

		//Endereço
		dummy1 = (EditText) findViewById(R.id.editLatLng);
		endereco = dummy1.getText().toString().trim();

		validade = config.getString("cfg_validade", "0");
		View sa = findViewById(R.id.spRaios);
		switch(Integer.parseInt(validade)){
		default:
		case 0:	validade = "30min"; break;
		case 1:	validade = "1h"; break;
		case 2:	validade = "2h"; break;
		case 3:	validade = "4h"; break;
		case 4:	validade = "8h"; break;
		case 5:	validade = "16h"; break;
		}
		

		previewAlerta.setText(Html.fromHtml("Neste alerta, " + 
				"<b>" + contato + " (" + numero + ")</b> <br /> " +
				" será avisado por <b>" + metodo + "</b>" +  
				" se dentro de (<b>" + validade + "</b>) <br />" +
				"estiver a <b>" + distancia + "</b> de " +
				"<b>" + endereco + "</b>" ));  
		
		//TODO checar se já existe listener para evitar problemas de vazamento de memória
		if(previewAlerta.isClickable()){
			return;
		}
		OnClickListener listener1 = new OnClickListener(){
			public void onClick(View v){
				Intent i = new Intent(RideCall.this, RideCallConfig.class);        
				startActivity(i);
			}
		};
		previewAlerta.setOnClickListener(listener1);
		previewAlerta.setClickable(true);
	}


	//Habilita e desabilita controles para evitar mal funcionamento
	public void atualizaControles(){
		Context ctx = getApplicationContext();

		ToggleButton btnRegistraAlerta = (ToggleButton) 
		findViewById(R.id.btnRegistrarAlerta);

		//Configura o espaço de alerta/msg para informar se não tem gps
		//E desabilita o botão de alerta
		Log.d(APPTAG, "Testando estado gps");
		if ( lm.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
			Log.d(APPTAG, "GPS ativo... ativando funcionamento normal dos botões");
			btnRegistraAlerta.setEnabled(true);
			
			tratamentoBotaoRegistroAlerta();
			
		} else {
			Log.d(APPTAG, "GPS desligado... desativando botões");
			btnRegistraAlerta.setEnabled(false);
			
			//Atualiza mensagem: esse método é eficiente ?
			updateStatusMessage("GPS desligado... desativando botões");
			
			//Se a pessoa clicar no botão irá informar a mensagem de ligar o gps
			//Registra o click para ativar/desativar o alerta de proximidade
			OnClickListener listener = new OnClickListener(){
				public void onClick(View v){
					buildAlertMessageNoGps();
				}
			};
			btnRegistraAlerta.setOnClickListener(listener);
			
		}

		//Configura o estado do botão de registro do alerta
		if(eAlerta.existPendingIntent(ctx)){
			Log.d(APPTAG, "Já existia um alerta para esse contato e local, ativando");
			btnRegistraAlerta.setChecked(true);
		} else {
			Log.d(APPTAG, "Não existia um alerta para esse contato e local");
		}

	}


	//Principio: reconhecer ao invés de relembrar
	public void updateStatusMessage(String msg){
		//Informar o usuário que precisa ligar o gps para que o programa funcione
		//por isso o botão de registro está desabilitado
		Log.d(APPTAG, "Informar atividade necessária: trocar estado do GPS");
		Log.d(APPTAG, "Informar atividade necessária: " + msg);
		
		TextView previewAlerta = (TextView)findViewById(R.id.preview_alerta);
		
		previewAlerta.setText(Html.fromHtml("GPS desligado... toque aqui!"));
		
	}



	private void updateUI(){

		//atualiza controles no change de objetos
		atualizaControles();

		//atualiza preview do alerta
		syncEntidadeAlerta();

		//atualiza preview do alerta
    if ( config.getBoolean("enablepreview", false)){
    	atualizaPreview();
    }
		
	}


}

